package db

import (
	"github.com/gomodule/redigo/redis"
	"log"
	"time"
	"ulcdkey/conf"
)

var cdkDb Cache

func init() {
	redisConf := conf.Conf.Redis
	cdkDb = NewRedisCache(redisConf.Db, redisConf.PassWord, redisConf.Host, time.Duration(redisConf.DefaultExpiration))
}

type Cache struct {
	pool              *redis.Pool
	defaultExpiration time.Duration
}

// 返回cache 对象, 在多个工具之间建立一个 中间初始化的时候使用
func NewRedisCache(db int, password, host string, defaultExpiration time.Duration) Cache {
	pool := &redis.Pool{
		MaxActive:   100,                              //  最大连接数，即最多的tcp连接数，一般建议往大的配置，但不要超过操作系统文件句柄个数（centos下可以ulimit -n查看）
		MaxIdle:     100,                              // 最大空闲连接数，即会有这么多个连接提前等待着，但过了超时时间也会关闭。
		IdleTimeout: time.Duration(100) * time.Second, // 空闲连接超时时间，但应该设置比redis服务器超时时间短。否则服务端超时了，客户端保持着连接也没用
		Wait:        true,                             // 当超过最大连接数 是报错还是等待， true 等待 false 报错
		Dial: func() (redis.Conn, error) {
			conn, err := redis.Dial("tcp", host, redis.DialDatabase(db), redis.DialPassword(password))
			if err != nil {
				log.Println("NewRedisCache error,err=", err)
				return nil, err
			}
			return conn, nil
		},
	}
	return Cache{pool: pool, defaultExpiration: defaultExpiration}
}

// 判断所在的 key 是否存在
func (c Cache) Exist(name string) (bool, error) {
	conn := c.pool.Get()
	defer conn.Close()
	v, err := redis.Bool(conn.Do("EXISTS", name))
	return v, err
}

// 删除指定的键
func (c Cache) Delete(keys ...interface{}) (bool, error) {
	conn := c.pool.Get()
	defer conn.Close()
	v, err := redis.Bool(conn.Do("DEL", keys...))
	return v, err
}

// 迭代数据库中的数据库键
func (c Cache) Keys() (res []string, err error) {
	conn := c.pool.Get()
	defer conn.Close()
	res, err = redis.Strings(conn.Do("KEYS", "*"))
	return
}

/*     hash      */
// 删除指定的 hash 键
func (c Cache) Hdel(name, key string) (bool, error) {
	conn := c.pool.Get()
	defer conn.Close()
	var err error
	v, err := redis.Bool(conn.Do("HDEL", name, key))
	return v, err
}

// 查看hash 中指定是否存在
func (c Cache) HExists(name, field string) (bool, error) {
	conn := c.pool.Get()
	defer conn.Close()
	var err error
	v, err := redis.Bool(conn.Do("HEXISTS", name, field))
	return v, err
}

// 获取hash 的键的个数
func (c Cache) HLen(name string) (int, error) {
	conn := c.pool.Get()
	defer conn.Close()
	v, err := redis.Int(conn.Do("HLEN", name))
	return v, err
}

// 传入的 字段列表获得对应的值
func (c Cache) HMget(name string, fields ...string) ([]interface{}, error) {
	conn := c.pool.Get()
	defer conn.Close()
	args := []interface{}{name}
	for _, field := range fields {
		args = append(args, field)
	}
	value, err := redis.Values(conn.Do("HMGET", args...))

	return value, err
}

func (c Cache) HSet(name string, key string, value interface{}) (err error) {
	conn := c.pool.Get()
	defer conn.Close()

	_, err = conn.Do("HSET", name, key, value)
	return
}

// 获取单个hash 中的值
func (c Cache) HGet(name, field string) (res string, err error) {
	conn := c.pool.Get()
	defer conn.Close()
	res, _ = redis.String(conn.Do("HGET", name, field))
	return
}

// 获取hash表所有的value
func (c Cache) HVals(name string) (res string, err error) {
	conn := c.pool.Get()
	defer conn.Close()
	res, _ = redis.String(conn.Do("HVALS", name))
	return
}

// 获取所有哈希表中的字段
func (c Cache) HKEYS(name string) (res []string, err error) {
	conn := c.pool.Get()
	defer conn.Close()
	res, _ = redis.Strings(conn.Do("HKEYS", name))
	return
}

// 迭代哈希表中的键值对。
func (c Cache) HGETALL(name string) (res map[string]string, err error) {
	conn := c.pool.Get()
	defer conn.Close()
	res, err = redis.StringMap(conn.Do("HGETALL", name))
	return
}
